package com.github.core.parse.spel;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import java.util.Optional;
import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypedValue;

/**
 *
 */
public class SpelJsonPropertyAccessor implements PropertyAccessor {

    @Override
    public Class<?>[] getSpecificTargetClasses() {
        return new Class<?>[]{JSONObject.class, JSONArray.class, String.class, JSON.class};
    }

    @Override
    public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
        Object rootObjectValue = context.getRootObject().getValue();
        if (target instanceof JSON || rootObjectValue instanceof JSON) {
            return true;
        } else if (target instanceof String) {
            try {
                return canRead(context, JSONUtil.parse(target), name);
            } catch (Exception e) {
                return false;
            }
        }
        return false;
    }

    @Override
    public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
        Object rootObjectValue = context.getRootObject().getValue();
        Object value = null;
        if (target instanceof JSON) {
            value = JSONUtil.getByPath(JSONUtil.parse(target), name);
        }
        if (ObjectUtil.isEmpty(value) && ObjectUtil.isNotEmpty(rootObjectValue) && JSONUtil.isJson(rootObjectValue.toString())) {
            value = JSONUtil.getByPath(JSONUtil.parse(rootObjectValue), name);
        }
        return new TypedValue(Optional.ofNullable(value).orElse(""));
    }

    @Override
    public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
        return true;
    }

    @Override
    public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {
        JSON targetObj = JSONUtil.parse(target);
        JSONUtil.putByPath(targetObj, name, newValue);
    }
}
